package com.android.xk.mask

import android.os.Environment
import android.os.StatFs
import io.netty.buffer.ByteBuf
import io.reactivex.Flowable
import io.reactivex.Maybe
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import java.io.BufferedReader
import java.io.InputStreamReader
import java.nio.charset.Charset
import java.text.NumberFormat
import java.text.SimpleDateFormat
import java.util.*


private val HEX_CHARS = "0123456789ABCDEF".toCharArray()

fun ByteArray.toHex(): String
{
    val result = StringBuffer()

    forEach {
        val octet = it.toInt()
        val firstIndex = (octet and 0xF0).ushr(4)
        val secondIndex = octet and 0x0F
        result.append(HEX_CHARS[firstIndex])
        result.append(HEX_CHARS[secondIndex])
    }

    return result.toString()
}


fun ByteArray.toStr(): String
{
    var len = 0
    for (i in this.indices)
    {
        if (this[i] == 0x00.toByte())
        {
            len = i
            break
        }
    }
    return String(this, 0, len, Charset.defaultCharset())
}

fun IntArray.toHex(): String
{
    val result = StringBuffer()

    forEach {
        val firstIndex = (it and 0xF0).ushr(4)
        val secondIndex = it and 0x0F
        result.append(HEX_CHARS[firstIndex])
        result.append(HEX_CHARS[secondIndex])
    }

    return result.toString()
}

fun <T> Observable<T>.onUI(): Observable<T> = observeOn(AndroidSchedulers.mainThread())

fun <T> Observable<T>.onUI(onNext: (T) -> Unit): Disposable =
        observeOn(AndroidSchedulers.mainThread()).subscribe(onNext)

fun <T> Observable<T>.onUI(onNext: (T) -> Unit, onError: (Throwable) -> Unit): Disposable =
        observeOn(AndroidSchedulers.mainThread()).subscribe(onNext, onError)

fun <T> Observable<T>.onIO(): Observable<T> = subscribeOn(Schedulers.io())

fun <T> Single<T>.onIO(): Single<T> = subscribeOn(Schedulers.io())

fun <T> Single<T>.onUI(onNext: (T) -> Unit, onError: (Throwable) -> Unit): Disposable =
        observeOn(AndroidSchedulers.mainThread()).subscribe(onNext, onError)

fun <T> Maybe<T>.onIO(): Maybe<T> = subscribeOn(Schedulers.io())

fun <T> Maybe<T>.onUI(onNext: (T) -> Unit, onError: (Throwable) -> Unit): Disposable =
        observeOn(AndroidSchedulers.mainThread()).subscribe(onNext, onError)

fun <T> Flowable<T>.onIO(): Flowable<T> = subscribeOn(Schedulers.io())

fun <T> Flowable<T>.onUI(onNext: (T) -> Unit, onError: (Throwable) -> Unit): Disposable =
        observeOn(AndroidSchedulers.mainThread()).subscribe(onNext, onError)

/**
 * 获取cpu使用率
 */
fun getProcessCpuRate(): Int
{
    val sb = StringBuilder()

    var rate = 0

    val p = Runtime.getRuntime().exec("top -n 1")

    val br = BufferedReader(InputStreamReader(p.inputStream))
    var result: String? = null
    while (br.readLine().also { result = it } != null)
    {
        if (result.isNullOrBlank())
        {
            continue
        }
        else
        {
            val CPUusr = result?.split("%")
            sb.append("USER:" + (CPUusr?.get(0) ?: 0) + "\n")
            val CPUusage = CPUusr?.get(0)?.split("User")
            val SYSusage = CPUusr?.get(1)?.split("System")
            sb.append(
                    "CPU:" + (CPUusage?.get(1)?.trim()
                            ?: 0) + " length:" + CPUusage?.get(1)?.trim()?.length + "\n"
            )
            sb.append(
                    "SYS:" + (SYSusage?.get(1)?.trim()
                            ?: 0) + " length:" + SYSusage?.get(1)?.trim()?.length + "\n"
            )
            rate = (CPUusage?.get(1)?.trim()?.toInt() ?: 0) + (SYSusage?.get(1)?.trim()?.toInt()
                    ?: 0)
            break
        }
    }

    return rate
}

/**
 * 获取内存使用率
 */
fun getMemRate()
{

}

/**
 * 获取磁盘使用率
 *
 */
fun getDiskRate(): Int
{
    val path = Environment.getExternalStorageDirectory()
    val stat = StatFs(path.path)
    val blockSize = stat.blockSizeLong
    val totalBlocks = stat.blockCountLong
    val availableBlocks = stat.availableBlocksLong
    val totalSize = totalBlocks * blockSize
    val availSize = availableBlocks * blockSize
    return ((totalSize - availSize) / totalSize.toFloat() * 100).toInt()
}

fun ByteBuf.readString(len: Int): String
{
    val v = ByteArray(len)
    this.readBytes(v)
    return v.toStr()
}

fun ByteBuf.writeString(value: String?, len: Int)
{
    if (value.isNullOrBlank()) return

    val buff = value.toByteArray()
    val des = buff.copyOf(len)

//    for (i in des.indices)
//    {
//        if (buff.size < len)
//        {
//            des[i] = buff[i]
//        }
//        else
//        {
//            des[i] = 0
//        }
//    }
    this.writeBytes(des)
}

fun getCurrentDateString(): String
{
    val d = Date()
    val sdf = SimpleDateFormat("yyyyMMddHHmmss")
    return sdf.format(d)
}